package com.rymcu.forest.auth;

import com.rymcu.forest.dto.TokenUser;
import com.rymcu.forest.entity.Role;
import com.rymcu.forest.entity.User;
import com.rymcu.forest.service.RoleService;
import com.rymcu.forest.util.UserUtils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import jakarta.annotation.Resource;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * JWT Authentication Provider for Spring Security 6
 *
 * @author ronger
 */
@Slf4j
@Component
public class JwtAuthenticationProvider implements AuthenticationProvider {

    @Resource
    private RoleService roleService;

    private final SecretKey key;

    public JwtAuthenticationProvider() {
        this.key = Keys.hmacShaKeyFor(JwtConstants.JWT_SECRET.getBytes(StandardCharsets.UTF_8));
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        if (!(authentication instanceof JwtAuthenticationToken)) {
            return null;
        }

        String token = (String) authentication.getCredentials();

        try {
            // 验证JWT token
            Claims claims = Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token)
                    .getBody();

            // 获取用户信息
            String username = claims.getSubject();
            if (StringUtils.isBlank(username)) {
                throw new BadCredentialsException("JWT token has no subject");
            }

            // 从token中获取用户ID
            Object userIdObj = claims.get("userId");
            if (userIdObj == null) {
                throw new BadCredentialsException("JWT token has no userId");
            }

            Long userId = null;
            if (userIdObj instanceof Integer) {
                userId = ((Integer) userIdObj).longValue();
            } else if (userIdObj instanceof Long) {
                userId = (Long) userIdObj;
            } else if (userIdObj instanceof String) {
                userId = Long.parseLong((String) userIdObj);
            }

            if (userId == null) {
                throw new BadCredentialsException("Invalid userId in JWT token");
            }

            // 构建TokenUser
            TokenUser tokenUser = new TokenUser();
            tokenUser.setIdUser(userId);
            tokenUser.setAccount(username);
            tokenUser.setToken(token);

            // 获取claims中的其他信息
            Object nickname = claims.get("nickname");
            if (nickname != null) {
                tokenUser.setNickname(nickname.toString());
            }

            Object avatarUrl = claims.get("avatarUrl");
            if (avatarUrl != null) {
                tokenUser.setAvatarUrl(avatarUrl.toString());
            }

            // 获取scope/权限
            Object scopeObj = claims.get("scope");
            if (scopeObj instanceof List) {
                @SuppressWarnings("unchecked")
                List<String> scopeList = (List<String>) scopeObj;
                tokenUser.setScope(Set.copyOf(scopeList));
            }

            // 获取用户权限
            List<SimpleGrantedAuthority> authorities = getUserAuthorities(userId);

            // 创建认证成功的token
            return new JwtAuthenticationToken(token, tokenUser, authorities);

        } catch (Exception e) {
            log.error("JWT authentication failed: {}", e.getMessage(), e);
            throw new BadCredentialsException("Invalid JWT token", e);
        }
    }

    private List<SimpleGrantedAuthority> getUserAuthorities(Long userId) {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();

        try {
            User user = new User();
            user.setIdUser(userId);

            List<Role> roles = roleService.selectRoleByUser(user);

            // 添加角色权限
            for (Role role : roles) {
                if (StringUtils.isNotBlank(role.getInputCode())) {
                    authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getInputCode()));
                    authorities.add(new SimpleGrantedAuthority(role.getInputCode()));
                }
            }

            // 添加基础用户权限
            authorities.add(new SimpleGrantedAuthority("user"));

        } catch (Exception e) {
            log.error("Failed to load user authorities for userId: {}", userId, e);
            throw new InsufficientAuthenticationException("Failed to load user authorities", e);
        }

        return authorities;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return JwtAuthenticationToken.class.isAssignableFrom(authentication);
    }
}